package com.pycredit.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.pycredit.bean.CostAnalyzerConfigParam;
import com.pycredit.bean.CostAnalyzerParam;
import com.pycredit.bean.CostAnalyzerResult;
import com.pycredit.bean.CostBaseAnalyzerParam;
import com.pycredit.bean.CostUserAnalyzerParam;
import com.pycredit.bean.ServiceTypePersonCostParam;
import com.pycredit.bean.ServiceTypeSpecialCostParam;
import com.pycredit.constance.CodeConstance;
import com.pycredit.constance.MsgConstance;
import com.pycredit.exception.BizException;
import com.pycredit.service.ICustomerProjectAnalyzer;
import com.pycredit.service.IServiceTypeCostAnalyzer;
import com.pycredit.type.ExceptionType;
import com.pycredit.type.PersonType;
import com.pycredit.type.ServiceChildType;
import com.pycredit.type.ServiceType;
import com.pycredit.util.MathUtil;
import com.pycredit.util.ParamFormatUtil;

/**
 * @category 客户项目价格核算
 * 
 * @author yiz
 * @date 2016年5月23日 上午11:28:33
 * @version 1.0.0 
 * @copyright pycredit.cn 
 */
public class CustomerProjectAnalyzer implements ICustomerProjectAnalyzer {

	private IServiceTypeCostAnalyzer serviceTypeCostAnalyzer = new ServiceTypeCostAnalyzer();
	/**
	 * @category 指标权重， 分别对应：1注册资金、2行业排名、3计划查询量、4信息查询用途、5单位性质、6信息查询类型、7成立日期、8企业人数
	 */
	private static String[] userRiskParams = { "-1,0.0992;1000,0.1556;5000,0.2012;460000,0.2362",
			"权威,0.1551;领先,0.1363;较好,0.1063;中等,0.0911;一般,0.0621", "大,0.1405;中,0.1181;小,0.0825;极小,0.0698",
			"信用报告基础信息,0.0591;身份核查,0.0483;其他,0.0247", "国企,0.0582;民企,0.042;混合,0.0355",
			"接口,0.043;批量,0.0324;共享平台,0.0201;自助核查,0.0169", "14,0.0469;10,0.0364;6,0.0256;-1,0.0129",
			"500,0.0411;100,0.0322;30,0.0201;-1,0.0096" };

	/**
	 * @category 多记录输入参数计算客户项目价格核算，服务参数顺序必须为   接口核查，共享平台，自助核查,批量核查 ，否则将会计算错误
	 * @category costAnalyzerConfigParam 客户成本分析基础配置参数
	 * @param costUserAnalyzerParam 客户分析用户基础参数，客户的信息，如行业排名，查询量大小等
	 * @param costAnalyzerParams  客户分析参数
	 * @param costBaseAnalyzerParam 基础数据参数，代码中心的基础数据，用于计算平均情况
	 * @param serviceTypeSpecialCostParams 各服务支出用户项目支出 软硬件支出情况
	 * @param serviceTypePersonCostParams 各个服务类型人工花费成本A,B,C类人员
	 * @return
	 */
	@Override
	public CostAnalyzerResult<String> getMultiCostPay(CostAnalyzerConfigParam costAnalyzerConfigParam,
			CostUserAnalyzerParam costUserAnalyzerParam, List<CostAnalyzerParam> costAnalyzerParams,
			CostBaseAnalyzerParam costBaseAnalyzerParam, List<ServiceTypeSpecialCostParam> serviceTypeSpecialCostParams,
			List<ServiceTypePersonCostParam> serviceTypePersonCostParams) {
		CostAnalyzerResult<String> analyzerResult = new CostAnalyzerResult<String>();
		StringBuffer resultAll = new StringBuffer();
		String finalResult = "";
		if (null == costAnalyzerConfigParam || null == costUserAnalyzerParam || null == costAnalyzerParams
				|| costAnalyzerParams.size() == 0 || null == costBaseAnalyzerParam
				|| null == serviceTypeSpecialCostParams || serviceTypeSpecialCostParams.size() == 0
				|| null == serviceTypePersonCostParams || serviceTypePersonCostParams.size() == 0) {
			analyzerResult.setCode(CodeConstance.ERROR);
			analyzerResult.setMsg(MsgConstance.ATTR_ERROR);
			return analyzerResult;
		}
		List<Double> nums = new ArrayList<Double>();
		for (CostAnalyzerParam costAnalyzerParam : costAnalyzerParams) {
			nums.add(costAnalyzerParam.getDataNum());
		}

		double result = 0;
		try {
			//得到可计算的参数,对参数进行分类以及分配分摊系数
			costAnalyzerParams = serviceTypeCostAnalyzer.getLastCostAnalyzerParam(costAnalyzerParams);
			//代码中心全部人员费用支出参数
			double codeCenterTotleFee = costBaseAnalyzerParam.getTotleFee();
			//产品服务数量
			List<Double> serviceProductNums = costBaseAnalyzerParam.getServiceProductNums();
			//接口核查（比对）数据量，共享平台数据量，自助核查数据量,批量核查数据量,必须按照顺序传入
			List<Double> serviceNums = costBaseAnalyzerParam.getServiceNums();
			//日常办公费，咨询费，水费，电费，交通费，取暖费，物业费，差旅费，会议费，培训费，招待费，宣传费用
			List<Double> dailyFeeCosts = costBaseAnalyzerParam.getDailyFeeCosts();
			//硬件成本，软件开发，购买软件，基础设施，维护保障，其他维护费用，
			List<Double> maintenanceFeeCosts = costBaseAnalyzerParam.getMaintenanceFeeCosts();
			//项目专项支出列表
			Map<String, Double> specialCostByType = serviceTypeCostAnalyzer
					.specialCostByType(serviceTypeSpecialCostParams);

			//得到请求的配置参数=========
			//工作时间
			Integer workDay = costAnalyzerConfigParam.getWorkDay();
			Integer dailyDeal = costAnalyzerConfigParam.getDailyDeal();
			Double c = costAnalyzerConfigParam.getCodeC();
			Double r = costAnalyzerConfigParam.getUserR();
			Map<String, Double> personSalary = ParamFormatUtil
					.getPersonSalaryFormat(costAnalyzerConfigParam.getPersonSalarys());

			List<Double> dailyFeeRatio = ParamFormatUtil
					.getDailyFeeRatioFormat(costAnalyzerConfigParam.getDailyFeeRatios());

			List<List<String[]>> userRiskWeight = ParamFormatUtil.getUserRiskParamFormat(userRiskParams);
			//字段系数
			Map<String, Double> filedType = ParamFormatUtil
					.getFiledTypeFormat(costAnalyzerConfigParam.getFiledCostRatios());
			//基础成本
			Map<String, Double> productForm = ParamFormatUtil
					.getProductBaseCostFormat(costAnalyzerConfigParam.getProductBaseCosts());
			//得到用户成本列表  
			Map<String, Double> personCostByType = serviceTypeCostAnalyzer.personCostByType(serviceTypePersonCostParams,
					workDay, personSalary);
			//用户成本列表
			List<Double> personCostList = serviceTypeCostAnalyzer.personCostList(serviceTypePersonCostParams, workDay,
					personSalary);
			// 所有产品的人员费用参数
			double personTotleCost = serviceTypeCostAnalyzer.personTotleFee(serviceProductNums, personCostList);
			//人工成本
			Map<String, Double> businessServiceCostAvgByType = serviceTypeCostAnalyzer.businessServiceCostAvgByType(
					codeCenterTotleFee, personTotleCost, dailyFeeCosts, maintenanceFeeCosts, serviceNums, dailyFeeRatio,
					c);

			//权重
			double weight = serviceTypeCostAnalyzer.calcWeight(costUserAnalyzerParam, userRiskWeight);
			//用户风险评分
			double calcUserRiseGrade = serviceTypeCostAnalyzer.calcUserRiseGrade(weight);
			//用户风险系数
			double userRiskcoeff = serviceTypeCostAnalyzer.calcUserRiseCoeff(calcUserRiseGrade, r); //测试数据1.05;//

			double batchFee = personSalary.get("person_" + PersonType.A.getType());
			//人工比对（核查）成本
			double personCompareCost = serviceTypeCostAnalyzer.artificialCost(dailyDeal, batchFee, workDay);
			//计算成本
			List<Double> getResult = new ArrayList<Double>();
			List<Boolean> getLimit = new ArrayList<Boolean>();
			for (CostAnalyzerParam costAnalyzerParam : costAnalyzerParams) {
				Map<String, Boolean> limitMap = new HashMap<String, Boolean>();
				double thisResult = getSingleCostPay(costAnalyzerParam, costBaseAnalyzerParam, specialCostByType,
						businessServiceCostAvgByType, personCostByType, userRiskcoeff, personCompareCost, filedType,
						productForm, limitMap);
				getResult.add(thisResult);
				getLimit.add(limitMap.get("limit"));
				result = MathUtil.add(result, thisResult);
			}
			//总价格四舍五入
			BigDecimal bigDecimal = new BigDecimal(result);
			result = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
			resultAll.append("项目总价格:").append(result).append("万元。");
			for (int i = 0; i < costAnalyzerParams.size(); i++) {
				CostAnalyzerParam costAnalyzerParam = costAnalyzerParams.get(i);
				double thisResult = getResult.get(i);
				Boolean limit = getLimit.get(i);
				double avg = 0;
				if (thisResult != 0) {
					avg = MathUtil.div(getResult.get(i), nums.get(i), 7);
				}
				bigDecimal = new BigDecimal(avg);
				avg = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
				resultAll.append(costAnalyzerParam.getServiceChildType().getName()).append(":").append("项目价格")
						.append(getResult.get(i)).append("万元,").append("单价").append(avg).append("元/每条次");
				if (limit != null && limit) {
					resultAll.append("(查询量小于等于10W，按照10W进行计算);");
				} else {
					resultAll.append(";");
				}
			}

			if (null != resultAll) {
				finalResult = resultAll.substring(0, resultAll.length() - 1) + "。";
			}

		} catch (BizException e) {
			e.printStackTrace();
			analyzerResult.setCode(CodeConstance.ERROR);
			analyzerResult.setMsg(MsgConstance.CALC_ERROR);
			analyzerResult.setResult("-1");
			return analyzerResult;
		} catch (IllegalAccessException e) {
			e.printStackTrace();
			analyzerResult.setCode(CodeConstance.ERROR);
			analyzerResult.setMsg(MsgConstance.CALC_ERROR);
			analyzerResult.setResult("-1");
			return analyzerResult;
		}
		if (result <= 0) {
			analyzerResult.setCode(CodeConstance.FAIL);
			analyzerResult.setMsg(MsgConstance.CALC_ERROR);
			analyzerResult.setResult("-1");
		} else {
			analyzerResult.setCode(CodeConstance.OK);
			analyzerResult.setMsg(MsgConstance.CALC_SUCCESS);
			analyzerResult.setResult(finalResult);
		}
		return analyzerResult;
	}

	/**
	 * @category 
	 * @return
	 * @throws BizException 
	 */
	public double getSingleCostPay(CostAnalyzerParam costAnalyzerParam, CostBaseAnalyzerParam costBaseAnalyzerParam,
			Map<String, Double> specialCostByType, Map<String, Double> businessServiceCostAvgByType,
			Map<String, Double> personCostByType, double userRiskcoeff, double personCompareCost,
			Map<String, Double> filedType, Map<String, Double> productForm, Map<String, Boolean> limitMap)
			throws BizException {
		ServiceChildType serviceChildType = costAnalyzerParam.getServiceChildType();
		ServiceType serviceType = serviceChildType.getServiceType();
		String filed = costAnalyzerParam.getFiled();
		int productNum = costAnalyzerParam.getProductNum();
		double dataNum = costAnalyzerParam.getDataNum();
		double profitRatio = costAnalyzerParam.getProfitRatio();
		double sharingcoeff = costAnalyzerParam.getSharingcoeff();
		double quality = costAnalyzerParam.getQuality();
		boolean needPersonCompare = costAnalyzerParam.isNeedPersonCompare();
		// 得到服务类型
		String project = serviceType.getKey();
		//项目专项支出
		double specialCost = specialCostByType.get(project);

		//人工成本
		double personCost = personCostByType.get(project);
		if (dataNum <= 0) {
			limitMap.put("limit", true);
		}
		if (ServiceType.PLHC.getKey().equals(project)) {
			if (dataNum <= 10) {
				limitMap.put("limit", true);
			}
		}
		if (dataNum < 0) {
			dataNum = 0;
		}
		if (dataNum < 0) {
			throw new BizException(ExceptionType.CA_0003.getCode(),
					ExceptionType.CA_0003.getMsg() + serviceChildType.getName() + "预计数据查询量dataNum小于10");
		}

		//风险控制成本系数
		double riskcoeff = productForm.get(serviceChildType.getKey());

		//单位运营成本
		double unitOperatingCost = 0;
		try {
			unitOperatingCost = MathUtil.div(businessServiceCostAvgByType.get(project), 10000, 4);
		} catch (IllegalAccessException e) {
			throw new BizException(ExceptionType.CA_0005.getCode(), ExceptionType.CA_0005.getMsg());
		} catch (ArithmeticException e) {
			throw new BizException(ExceptionType.CA_0005.getCode(), ExceptionType.CA_0005.getMsg());
		}

		// 一般变动成本
		double generalChangeCost = serviceTypeCostAnalyzer.generalChangeCost(unitOperatingCost, productNum, dataNum,
				filedType.get("field_type_" + filed));
		//项目人工成本
		// 项目变动成本
		double projectChangeCost = serviceTypeCostAnalyzer.projectChangeCost(personCost, specialCost,
				filedType.get("field_type_" + filed));
		//产品变动成本  ，批量查询时，为机器处理成本
		double productChangeCost = serviceTypeCostAnalyzer.productChangeCost(generalChangeCost, projectChangeCost,
				sharingcoeff, riskcoeff);
		//产品成本 
		double productCost = 0;

		if (ServiceType.PLHC.getKey().equals(project)) {
			//批量处理人工处理成本
			double personDealCost = 0;
			if (needPersonCompare) {//当需要人工处理成本时
				personDealCost = serviceTypeCostAnalyzer.personDealCost(dataNum, quality, personCompareCost);
			}
			productCost = serviceTypeCostAnalyzer.productCostBatch(personDealCost, productChangeCost);
		} else {
			//产品基础成本
			double baseProductCost = serviceTypeCostAnalyzer.baseCost(unitOperatingCost, riskcoeff);
			//产品成本
			productCost = serviceTypeCostAnalyzer.productCost(baseProductCost, productChangeCost);
		}
		//客户项目价格
		double customProductPrice = serviceTypeCostAnalyzer.customProductPrice(productCost, profitRatio, userRiskcoeff);

		BigDecimal bigDecimal = new BigDecimal(customProductPrice);

		//四舍五入计算保留两位小数
		double result = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();

		//返回结果
		return result;
	}

}
